package com.group11.museum.backend.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.group11.museum.backend.bean.UserBean;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.*;

import java.util.*;

@RestController
public class UserController {

    final JdbcTemplate jdbcTemplate;

    public UserController(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }


    /**
     * 检查对象是否为null, 转换为SQL语句中的NULL
     * @param obj 目标对象
     * @return 返回包装后的值
     */
    private String checkNull(Object obj){
        if (obj == null){
            return "NULL";
        }
        return "'" + obj + "'";
    }

    /**
     *  获取插入用户信息的SQL语句
     * @param user 用于插入的User Bean
     * @return 返回SQL语句
     */
    private String getAddUserSQL(UserBean user){
        // 编辑插入用户信息的SQL语句

        return "insert into users(username, email, avatar, phone" +
                ", create_time, password) values(" + "'" + user.getUsername() + "'," +   // 必填
                checkNull(user.getEmail()) + "," +
                checkNull(user.getAvatar()) + "," +
                "'" + user.getPhone() + "'," +  //必填电话
                "'" + System.currentTimeMillis() + "'," + // 生成创建时间
                "'" + user.getPassword() + "')";
    }

    /**
     * 判断字段是否以及存在
     * @param key 字段
     * @param v 字段值
     * @return  符合该字段的行数
     */
    private String checkExist(String key, String v) throws BadSqlGrammarException{
        String sql = String.format("select count(*) num from users where %s='%s'", key, v);
        Map<String, Object> stringObjectMap = jdbcTemplate.queryForMap(sql);
        return stringObjectMap.get("num").toString();
    }

    /**
     * 获取用户UUID
     * @param key 字段
     * @param v 值
     * @return uuid
     */
    private String getUUID(String key, String v) throws EmptyResultDataAccessException {
        String sql = String.format("select uuid from users where %s='%s'", key, v);
        Map<String, Object> stringObjectMap = jdbcTemplate.queryForMap(sql);
        return stringObjectMap.get("uuid").toString();
    }

    /**
     * 判断电话或者email或用户名已经被注册
     * @param type 类型
     * @return {"code": "success/params error", "isExist":true/false}
     */
    @RequestMapping(value = "checkUserExist", method = RequestMethod.GET)
    public String checkUserExist(@RequestParam(value = "type") String type,
                                 @RequestParam(value = "key") String key) {
        // 创建返回json对象
        JSONObject res = new JSONObject();

        // 创建返回代码
        JSONObject returnCode = new JSONObject();
        returnCode.put("comment", "success");
        returnCode.put("code", "200");
        res.put("return", returnCode);

        try {
            // 判断键是否存在
            if(!checkExist(type, key).equals("0")){
                res.put("isExist", true);
                res.put("uuid", getUUID(type, key));
            }else{
                res.put("isExist", false);
            }
        }catch (BadSqlGrammarException e2){
            e2.printStackTrace();
            returnCode.put("comment", "unknown columns");
            returnCode.put("code", "304");

        }

        return res.toJSONString();
    }


    /**
     *
     * @return json 对象
     * code 302 代表用户重复
     * code 303 代表SQL语句语法错误
     * code 304 代表传递的用户信息json对象参数有误
     */
    @RequestMapping(value = "addUser", method = RequestMethod.POST)
    public String addUser(@RequestBody UserBean userBean) {
        // 创建返回json对象
        JSONObject res = new JSONObject();

        // 创建返回代码
        JSONObject returnCode = new JSONObject();
        returnCode.put("comment", "success");
        returnCode.put("code", "200");
        res.put("return", returnCode);

        try{
//        System.out.println(userinfo);

            // 将json转换为javabean
//        UserBean userBean = JSON.parseObject(userinfo, new TypeReference<UserBean>(){});
            String sql = getAddUserSQL(userBean);
//        System.out.println(sql);
            int rows = jdbcTemplate.update(sql);

            if (rows!=1){
                res.put("code", "fail to add new user");
            }else{
                String uuid = jdbcTemplate.queryForMap("select uuid from users where phone='" + userBean.getPhone() + "'")
                        .get("uuid").toString();
                String encodePassword = new SimpleHash("MD5", userBean.getPassword()
                        , uuid, 1).toHex();
                jdbcTemplate.update("update users set password='" + encodePassword + "'" + " where phone='"
                        + userBean.getPhone() + "'");
            }
        }catch (DuplicateKeyException duplicateKeyException){
            returnCode.put("comment", "duplicated user error");
            returnCode.put("code", "302");

        } catch (BadSqlGrammarException badSqlGrammarException){
            badSqlGrammarException.printStackTrace();
            returnCode.put("comment", "sql grammar error");
            returnCode.put("code", "303");
        } catch (Exception e){
            e.printStackTrace();
            returnCode.put("comment", "param error");
            returnCode.put("code", "304");
        }
        return res.toJSONString();
    }


    /**
     * 用户登录 检查密码和账号
     * 前提：用户存在
     * @param type  支持email, phone, username的登录方式
     * @param key
     * @param passwd
     * @param isReturnInfo
     * @return {"code":"success", "loginStatus":"0/1", "loginInfo":"xxx"}
     */
    @RequestMapping(value = "login", method = RequestMethod.PUT)
    public String login(@RequestParam(value = "type") String type,
                                  @RequestParam(value = "key") String key,
                                  @RequestParam(value = "passwd") String passwd,
                        @RequestParam(value = "isPasswdEncode", defaultValue = "false", required = false) boolean isPasswdEncode,
                        @RequestParam(value = "isReturnInfo", defaultValue = "true", required = false) boolean isReturnInfo){
        // 创建返回json对象
        JSONObject res = new JSONObject();

        // 创建返回代码
        JSONObject returnCode = new JSONObject();
        returnCode.put("comment", "success");
        returnCode.put("code", "200");
        res.put("return", returnCode);

        // 判断type值是否合法
        if (!type.equals("email") && !type.equals("phone") && !type.equals("username")){
            returnCode.put("comment", "unknown columns");
            returnCode.put("code", "304");
            return res.toJSONString();
        }

        // 检查密码
        String num;

        try {
            if (! isPasswdEncode){
                // 对密码进行加密
                passwd = new SimpleHash("MD5", passwd, getUUID(type, key), 1).toHex();
            }
            String sql = String.format("select count(*) num from users where %s='%s' and password='%s'", type, key, passwd);
            num = jdbcTemplate.queryForMap(sql).get("num").toString();
        } catch (EmptyResultDataAccessException e) {
            returnCode.put("comment", "user not exist");
            returnCode.put("code", "306");
            res.put("loginStatus", "0");
            return res.toJSONString();
        }

        // 密码错误返回
        if (num.equals("0")){
            returnCode.put("comment", "password incorrect");
            returnCode.put("code", "305");
            res.put("loginStatus", "0");
        }else {
            res.put("loginStatus", "1");
            // 生成 session 更新数据库
            String session = new SimpleHash("MD5", (System.currentTimeMillis()+""), type+key, 1).toHex();
            String updateSql = String.format("update users set session='%s' where %s='%s'", session, type, key);
            jdbcTemplate.update(updateSql);
            res.put("session", session);
            if (isReturnInfo){ // 返回用户信息
                res.put("loginInfo", getUserInfo(type, key));
            }else{
                res.put("loginInfo", "登录成功");
            }
        }
        return res.toJSONString();
    }

    /**
     * 更新用户信息
     * 前提：用户存在
     * @param session 支持session的登录方式
     */
    @RequestMapping(value = "updateUserInfo", method = RequestMethod.PUT)
    public String updateUserInfo(@RequestBody String info,
                              @RequestParam(value = "") String session){

        // 创建返回json对象
        JSONObject res = new JSONObject();

        // 创建返回代码
        JSONObject returnCode = new JSONObject();
        returnCode.put("comment", "success");
        returnCode.put("code", "200");
        res.put("return", returnCode);

        // 检查是否有不合法字段
        String[] fields = {"password", "username", "uuid", "email", "session"};
        JSONObject userInfoJson = JSON.parseObject(info);

        for (String field : fields) {
            if (userInfoJson.containsKey(field)){
                returnCode.put("comment", "invalid authorization");
                returnCode.put("code", "311");
                return res.toJSONString();
            }
        }

        StringBuilder updateSql = new StringBuilder("update users set ");


        Iterator<String> iterator = userInfoJson.keySet().iterator();
        while (iterator.hasNext()){
            String key = iterator.next();
            updateSql.append(key).append("='").append(userInfoJson.get(key)).append("'");
            if (iterator.hasNext()){
                // 判断结尾
                updateSql.append(",");
            }
        }
        updateSql.append(" where session='").append(session).append("'");

        int update = jdbcTemplate.update(updateSql.toString());
        if (update!=1){
            returnCode.put("comment", "user does not exist");
            returnCode.put("code", "306");
        }
        return res.toJSONString();
    }

    /**
     * 删除session 退出登录
     * 前提：用户存在
     * @param session 支持session的登录方式
     */
    @RequestMapping(value = "deleteSession", method = RequestMethod.PUT)
    public String updateToken(@RequestParam(value = "session") String session){

        // 创建返回json对象
        JSONObject res = new JSONObject();

        // 创建返回代码
        JSONObject returnCode = new JSONObject();
        returnCode.put("comment", "success");
        returnCode.put("code", "200");
        res.put("return", returnCode);


        String sql = String.format("update users set session=NULL where session='%s'", session);
        int update = jdbcTemplate.update(sql);
        if (update!=1){
            returnCode.put("comment", "user does not exist");
            returnCode.put("code", "306");
        }
        return res.toJSONString();
    }

    /**
     * 获取用户信息
     * @param type email, phone, session, username
     * @param key
     * @return username, uuid, email, avatar, phone, gender, birthday, create_time, status, token
     */
    private JSONObject getUserInfo(String type, String key){


        String sql = String.format("select  username, uuid, email, avatar, phone, gender," +
                " birthday, create_time, status, token  from users where %s='%s'", type, key);
        Map<String, Object> stringObjectMap = jdbcTemplate.queryForMap(sql);
        JSONObject userJsonInfo = new JSONObject();
        for (String mapKey : stringObjectMap.keySet()) {
            userJsonInfo.put(mapKey, stringObjectMap.get(mapKey));
        }
        return userJsonInfo;
    }

}
